package com.tsfyun.common.base.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.EnumUtil;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.dto.EnumInfo;
import com.tsfyun.common.base.enums.domain.DomainTypeEnum;
import com.tsfyun.common.base.support.OperationEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @Description: 实体类读取工具类
 * @since Created in 2020/4/3 10:23
 */
@Slf4j
public class EntityUtil {

    private static final String  ENTITY_PACKAGE_PATH = "com.tsfyun.scm.entity";//实体类包路径

    private static final String DOMAIN_STATUS_PATH = "com.tsfyun.common.base.enums.domain";

    private static Map<String,Class> classMaps = new ConcurrentHashMap();//实体类简称和全路径映射

    private static Map<String,List<EnumInfo>> domainStatusMap = new ConcurrentHashMap();//单据状态映射

    private static Map<Class,List<EnumInfo>> domainStatusMapNew = new ConcurrentHashMap();//单据状态映射

    /**
     * 不扫描的枚举类
     */
    private static final List<String> excludeScan = new ArrayList<String>() {{
        add(DomainTypeEnum.class.getSimpleName());
    }};

    private Lock lock = new ReentrantLock();

    /**
     * 构造方法
     */
    private EntityUtil(){

    }

    /**
     * 内部类单例模式
     */
    private static class EntityUtilInstance{
        private static final EntityUtil instance = new EntityUtil();
    }

    public static EntityUtil getInstance(){
        return EntityUtilInstance.instance;
    }

    /**
     * 获取实体数据map
     * @return
     */
    public Map<String,Class> getData() {
        if(classMaps != null && !classMaps.isEmpty()) {
            return classMaps;
        }
        lock.lock();//加锁，防止并发重复写
        try {
            Set<Class<?>> classes = ClassUtil.scanPackage(ENTITY_PACKAGE_PATH);
            if (classes != null && classes.size() > 0) {
                for (Class clazz : classes) {
                    classMaps.put(clazz.getSimpleName(),clazz);
                }
            }
        } finally {
            lock.unlock();//解锁
        }
        return classMaps;
    }

    /**
     * 获取实体单据状态数据map
     * @return
     */
    public Map<String,List<EnumInfo>> getStatusData() {
        if(domainStatusMap != null && !domainStatusMap.isEmpty()) {
            return domainStatusMap;
        }
        lock.lock();//加锁，防止并发重复写
        try {
            Set<Class<?>> classes = ClassUtil.scanPackage(DOMAIN_STATUS_PATH);
            if (classes != null && classes.size() > 0) {
                for (Class clazz : classes) {
                    if(excludeScan.contains(clazz.getSimpleName()) || !clazz.isEnum() ||  !OperationEnum.class.isAssignableFrom(clazz)) {
                        continue;
                    }
                    List<EnumInfo> list = getEnumValueByClass(clazz);
                    domainStatusMap.put(clazz.getSimpleName().replace("Enum","").replace("enum","").replace("Status",""),list);
                    domainStatusMapNew.put(clazz,list);
                }
            }
        } finally {
            lock.unlock();//解锁
        }
        return domainStatusMap;
    }

    public static List<EnumInfo> getEnumValueByClass(Class tt) {
        LinkedHashMap<String, OperationEnum> domainEnumMap = EnumUtil.getEnumMap(tt);
        List<EnumInfo> list = Lists.newArrayList();
        domainEnumMap.forEach((k,v)->{
            EnumInfo enumInfo = new EnumInfo();
            enumInfo.setCode(v.getCode());
            enumInfo.setName(v.getName());
            list.add(enumInfo);
        });
        return list;
    }

    /**
     * 获取单据允许状态
     * @param operationEnum 单据状态枚举
     * @param excludeStatusCode  排除状态数组
     * @return
     */
    public String[] getPermitCodes(Class<? extends OperationEnum> operationEnum,String... excludeStatusCode) {
        EntityUtil.getInstance().getStatusData();
        Map<Class,List<EnumInfo>> domainStatusMapNew = EntityUtil.getInstance().domainStatusMapNew;
        List<EnumInfo> enumInfos = domainStatusMapNew.get(operationEnum);
        if(CollUtil.isNotEmpty(enumInfos)) {
            List<String> allStatusCode = enumInfos.stream().map(EnumInfo::getCode).collect(Collectors.toList());
            Optional.ofNullable(excludeStatusCode).ifPresent(r->{
                allStatusCode.removeAll(Arrays.asList(excludeStatusCode));
            });
            return allStatusCode.toArray(new String[allStatusCode.size()]);
        }
        return null;
    }

}
